#include "shadow2d.h"
#include "qgl.h"
#include <stdlib.h>
#include "math.h"
using namespace std;
#define GRID_SIZE 70
#define qMAX 4
#define a .5
#define b 2
#define C 2
Shadow2D::Shadow2D()
{
    m_grid = new float[1];

}

Shadow2D::~Shadow2D()
{
    delete m_grid;
}

void Shadow2D::populateGrid(Bud *bud, float maxw, float maxh)
{
    m_maxw = maxw;
    m_maxh = maxh;
    delete[] m_grid;
   m_grid = new float[GRID_SIZE * GRID_SIZE];
   for(int i = 0; i< GRID_SIZE * GRID_SIZE; i++){
       m_grid[i] = 0.0f;
   }

   this->recurPopulate(bud);

}

void Shadow2D::recurPopulate(Bud *bud){
    int startw, starth;
    int ind;
    if(!bud->aux){
        convertToIndex(bud->end,startw, starth);
        for(int q =0 ; q<qMAX; q++){
            for(int p = -q; p<=q; p++){
                if((starth + q )< GRID_SIZE && (startw + p >= 0) && (startw +p < GRID_SIZE)){
                    ind = startw + p + (starth + q) * GRID_SIZE;
                    m_grid[ind] += a* pow((double) b,(double) -q);
                }
            }
        }
    }
    else
        recurPopulate(bud->aux);

    if(!bud->term){
        convertToIndex(bud->end,startw, starth);
        for(int q =0 ; q<qMAX; q++){
            for(int p = -q; p<=q; p++){
                if((starth + q )< GRID_SIZE && (startw + p > 0) && (startw +p < GRID_SIZE)){
                    ind = startw + p + (starth + q) * GRID_SIZE;
                    m_grid[ind] += a* pow((double) b,(double) -q);
                }
            }
        }
    }
    else
        recurPopulate(bud->term);
}

inline void Shadow2D::convertToIndex(float3 loc, int &w, int &h){
    w = (int) ((loc.x / m_maxw) * GRID_SIZE + .5);
    h =  (int) (GRID_SIZE - ((loc.y / m_maxh) * GRID_SIZE) + .5) ;
}

inline void Shadow2D::indexToXY(int w, int h, float3 &loc){
    loc.x = ((float) w)/ ((float) GRID_SIZE) * m_maxw;
    loc.y = ((float) GRID_SIZE - (float) h)/ ((float) GRID_SIZE) * m_maxw;
}

void Shadow2D::queryQ(Bud *bud){
    int w,h;
    convertToIndex(bud->end, w, h);
    int ind = w + GRID_SIZE*h;
    if(!bud->aux){
        //float test = max(C - m_grid[ind] + a, 0.0);
        bud->aQ = max(C - m_grid[ind] + a, 0.0);
        int bw=0, bh =0;
        float min = 100.0;
        for(int i = -1; i<2; i++){
            for(int j = -1; j<2; j++){
                int tindx = (w + i) + (h+j)*GRID_SIZE;
                if(m_grid[tindx]< min && (i!=0 || j!=0)){
                    min = m_grid[tindx];
                    bh = h+j;
                    bw = w+i;
                }
                if(m_grid[tindx]== min && (rand()%100) <= 50 && (i!=0 || j!=0) ){
                    min = m_grid[tindx];
                    bh = h+j;
                    bw = w+i;
                }
            }
        }
        float3 dir(bw-w, h-bh,0);
        dir.normalize();
        bud->aV = dir;
    }
    else
        queryQ(bud->aux);
    if(!bud->term){
        bud->tQ = max(C - m_grid[ind] + a, 0.0);
        int bw=0, bh =0;
        float min = 100.0;
        for(int i = -1; i<2; i++){
            for(int j = -1; j<2; j++){
                int tindx = (w + i) + (h+j)*GRID_SIZE;
                if(m_grid[tindx]< min && (i!=0 || j!=0)){
                    min = m_grid[tindx];
                    bh = h+j;
                    bw = w+i;
                }
                if(m_grid[tindx]== min && (i!=0 || j!= 0) && (rand()%100) <= 50){
                    min = m_grid[tindx];
                    bh = h+j;
                    bw = w+i;
                }
            }
        }
        float3 dir(bw-w, h-bh,0);
        dir.normalize();
        bud->tV = dir;
    }
    else
        queryQ(bud->term);
}



void Shadow2D::draw(){
    float size = m_maxw / (float) GRID_SIZE;
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

    float3 loc;
    for(int i =0; i<GRID_SIZE; i++){
        for(int j =0 ; j< GRID_SIZE; j++){
            this->indexToXY(i,j+1,loc);
            glColor3f(.5, .5, .5);
            glBegin(GL_QUADS);
                glVertex2f(loc.x , loc.y);
                glVertex2f(loc.x + size, loc.y);
                glVertex2f(loc.x + size, loc.y + size);
                glVertex2f(loc.x, loc.y + size);
            glEnd();
        }
    }

    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
    for(int i =0; i<GRID_SIZE; i++){
        for(int j =0 ; j< GRID_SIZE; j++){
            this->indexToXY(i,j+1,loc);
            glColor4f(1.0, 0, 0, m_grid[i + GRID_SIZE*j]);
            //cout<<m_grid[i+m_w*j]<<endl;
            glBegin(GL_QUADS);
                glVertex2f(loc.x , loc.y);
                glVertex2f(loc.x + size, loc.y);
                glVertex2f(loc.x + size, loc.y + size);
                glVertex2f(loc.x, loc.y + size);
            glEnd();
        }
    }
    glDisable(GL_BLEND);
}
